package com.hsc.mvc.bind;

import com.hsc.mvc.MvcFile;
import com.hsc.mvc.ParameterSource;
import com.hsc.mvc.util.ConversionUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @author
 * @date 2025-06-02
 * @Description 实体类型的参数绑定器
 * ● 组装绑定器时，将其放在了list集合的最后一个
 * ● 按照逻辑， 其他的绑定器如果都不支持参数，我们就认为这应该是一个实体绑定操作
 * ● 既然放在了最后一个，到这里就一定要执行。
 * ● 绑定过程：就是通过反射获得对象的属性，以属性名为key，获得对应的参数值。
 */
public class EntityParameterBinder implements ParameterBindStrategy {
    @Override
    public Object bind(Parameter parameter, ParameterSource parameterSource) throws Exception {
        // 获取参数的Class
        Class<?> type = parameter.getType();
        // 根据Class 对象实例化对象
        Object object = type.getConstructor().newInstance();
        // 获取参数值 参数值从parameterSource 中获取  在前面已经设置保存有了
        // 通过类对象获取所有的方法
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            // 获取方法名
            String methodName = method.getName();
            // 截取set 方法中的字母 来得到key 值
            if (methodName.startsWith("set")) {
                //setUno ==>需要拿到 uno , setN --》需要拿到 n ;
                //去掉set--- UserNo / N
                String name = methodName.substring(3);
                if (name.length() == 1) {
                    // 如果只有一个 字母 说明 set 方法 参数只有一个字母
                    name = name.toLowerCase();
                } else {
                    name = name.substring(0, 1).toLowerCase() + name.substring(1);
                }
                // 方法中拿到所有的参数的Class 类型 一般情况下我们任务 set 方法只有一个参数
                Class<?> parameterType = method.getParameterTypes()[0];
                Object value;
                // 判断方法的参数类型是文件类型还是String 类型
                if (parameterType == MvcFile[].class || parameterType == MvcFile.class) {
                    value = parameterSource.getFileParam(name);
                } else {
                    value = parameterSource.getStringParam(name);
                }
                // 对属性进行赋值
                // 依然使用set 方法进行赋值
                //注意：这里还有一个问题 ， 起初这个value只有2种类型 String[],MvcFile[]
                //     所以还需要根据属性的具体类型，对value值进行一个转换处理
                //value = castType(value,paramType)
                // 这里策略模式 省去if-else 操作
                // value 我们拿到的原始值
                // paramType 需要转换为用户参数的具体类型
                value = ConversionUtil.convert(value, parameterType);
                // 反射执行set方法
                // 给对象的属性进行赋值
                method.invoke(object, value);
            }
        }
        // 返回赋值好的对象
        return object;
    }

    /**
     * 实体类的参数绑定器 我们始终进行支持
     *
     * @param parameter
     * @return
     */
    @Override
    public boolean isSupport(Parameter parameter) {
        return true;
    }
}
